#pragma once

template <class T, UINT uPngID>
class CPaintBkgnd : public CMessageMap
{
public:
	CPaintBkgnd() 
	{
		m_pImage = new CImage();
		m_pImage->LoadFromResource(_Module.get_m_hInstResource(), uPngID);
	//	LoadImageFromResource(m_pImage, uPngID);
		T* pT = static_cast<T*>(this);
		m_mapBrushs.Add(NULL, AtlGetStockBrush(HOLLOW_BRUSH));
	}

	~CPaintBkgnd() 
	{
		int nSize = m_mapBrushs.GetSize();
		for(int i = 0; i < nSize; i++)
		{
			DeleteObject(m_mapBrushs.GetValueAt(i));
		}

		m_mapBrushs.RemoveAll();
		delete m_pImage; 
	}

	BEGIN_MSG_MAP(CPaintBkgnd)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
		MESSAGE_HANDLER(WM_COMMAND, OnEnChangeCommand)
		//MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORDLG, OnCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColor)
	END_MSG_MAP()

	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) 
	{
		T* pT = static_cast<T*>(this);
		HDC hDC = (HDC)wParam;

		CRect rcClient;
		pT->GetClientRect(&rcClient);
		m_pImage->Draw(hDC, rcClient);
		return 0;  
	}

	LRESULT OnEnChangeCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == CBN_SELCHANGE)
		{
			T* pT = static_cast<T*>(this);
			CRect rcCtrl;
			CWindow wndCtrl((HWND) lParam);
			wndCtrl.GetClientRect(&rcCtrl);
			wndCtrl.ClientToScreen(&rcCtrl);
			pT->ScreenToClient(&rcCtrl);
			pT->InvalidateRect(&rcCtrl);
			pT->UpdateWindow();
		}
		else
		{
			bHandled = FALSE;
		}
		return 0;
	}

	LRESULT OnCtlColor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		HDC hDC = (HDC)wParam;
		HWND hWnd = (HWND)lParam;

	//	if (uMsg == WM_CTLCOLORSTATIC || uMsg == WM_CTLCOLOREDIT || uMsg == WM_CTLCOLORDLG)
		{
			::SetBkMode(hDC, TRANSPARENT);
			return (LRESULT)GetBrushHandle(hWnd);
		}

		bHandled = FALSE;
		return 0;
	}

protected:
	CImage* m_pImage;
	CSimpleMap<HWND, HBRUSH> m_mapBrushs;

	HBRUSH GetBrushHandle(HWND hWndCtl)
	{
		int nIndex = m_mapBrushs.FindKey(hWndCtl);

		if (nIndex == -1)
		{
			T* pT = static_cast<T*>(this);
			CRect rcCtrl;
			CWindow wndCtrl(hWndCtl);
			wndCtrl.GetClientRect(&rcCtrl);

			CMemoryDC dc(pT->GetDC(), rcCtrl);

			wndCtrl.ClientToScreen(&rcCtrl);
			pT->ScreenToClient(&rcCtrl);
			pT->UpdateWindow();

			dc.BitBlt(0, 0, rcCtrl.Width(), rcCtrl.Height(), pT->GetDC(), rcCtrl.left, rcCtrl.top, SRCERASE);
			dc.SelectBitmap(dc.m_hBmpOld);

			HBRUSH hBrush = ::CreatePatternBrush(dc.m_bmp);

			m_mapBrushs.Add(hWndCtl, hBrush);

			return hBrush;
		}
		else
		{
			return m_mapBrushs.GetValueAt(nIndex);
		}	
	}

	BOOL LoadImageFromResource(CImage* pImage, UINT nResID)
	{
		if (pImage == NULL) 
		{
			return FALSE;
		}
		pImage->Destroy();

		CResource res;

		if (!res.Load(_T("PNG"), MAKEINTRESOURCE(nResID)))
		{
			return FALSE;
		}

		LPVOID pResData = res.Lock();
		DWORD dwResSize = res.GetSize();
		BOOL bRet = FALSE;

		HGLOBAL hGlobal  =  GlobalAlloc(GMEM_MOVEABLE, dwResSize);
		void *pData = GlobalLock(hGlobal);
		memcpy(pData, pResData, dwResSize);
		GlobalUnlock(hGlobal);

		IStream * pStream = NULL;
		if (CreateStreamOnHGlobal(pData, TRUE,  &pStream) ==  S_OK)
		{
			bRet = SUCCEEDED(pImage->Load(pStream));
		}

		GlobalFree(hGlobal);

		return bRet;
	}
};